#include <iostream>
#include <vector>
#include <string>
#include <iomanip>
#include <sstream>
#include <algorithm>
#include <limits>

using namespace std;

// 日期结构体，用于日期处理和比较
struct Date {
    int year;
    int month;
    int day;
    
    Date(int y = 0, int m = 0, int d = 0) : year(y), month(m), day(d) {}
    
    // 转换为字符串
    string toString() const {
        stringstream ss;
        ss << setw(4) << setfill('0') << year << "-"
           << setw(2) << setfill('0') << month << "-"
           << setw(2) << setfill('0') << day;
        return ss.str();
    }
    
    // 检查是否为有效的日期
    bool isValid() const {
        if (year <= 0 || month < 1 || month > 12 || day < 1) return false;
        
        int daysInMonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
        if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
            daysInMonth[1] = 29; // 闰年2月有29天
        }
        return day <= daysInMonth[month - 1];
    }
    
    // 比较两个日期是否在同一个月
    bool isSameMonth(const Date& other) const {
        return year == other.year && month == other.month;
    }
    
    // 比较两个日期是否相等
    bool operator==(const Date& other) const {
        return year == other.year && month == other.month && day == other.day;
    }
    
    // 比较两个日期大小
    bool operator<(const Date& other) const {
        if (year != other.year) return year < other.year;
        if (month != other.month) return month < other.month;
        return day < other.day;
    }
};

// 解析日期字符串为Date对象
Date parseDate(const string& dateStr) {
    Date date;
    char dash1, dash2;
    istringstream ss(dateStr);
    ss >> date.year >> dash1 >> date.month >> dash2 >> date.day;
    
    if (ss.fail() || dash1 != '-' || dash2 != '-' || !date.isValid()) {
        return Date(0, 0, 0); // 无效日期
    }
    return date;
}

// 账单记录基类
class Record {
protected:
    Date date;
    double amount;
    string category;
    string note;
    
public:
    Record(const Date& d, double a, const string& c, const string& n)
        : date(d), amount(a), category(c), note(n) {}
    
    virtual ~Record() = default;
    
    const Date& getDate() const { return date; }
    double getAmount() const { return amount; }
    const string& getCategory() const { return category; }
    const string& getNote() const { return note; }
    
    virtual string getType() const = 0;
    virtual void display() const = 0;
};

// 收入记录
class Income : public Record {
public:
    Income(const Date& d, double a, const string& c, const string& n)
        : Record(d, a, c, n) {}
    
    string getType() const override { return "收入"; }
    
    void display() const override {
        cout << left << setw(12) << date.toString()
             << setw(10) << fixed << setprecision(2) << amount
             << setw(15) << category
             << note << endl;
    }
};

// 支出记录
class Expense : public Record {
public:
    Expense(const Date& d, double a, const string& c, const string& n)
        : Record(d, a, c, n) {}
    
    string getType() const override { return "支出"; }
    
    void display() const override {
        cout << left << setw(12) << date.toString()
             << setw(10) << fixed << setprecision(2) << amount
             << setw(15) << category
             << note << endl;
    }
};

// 预算信息
struct Budget {
    int year;
    int month;
    double limit;
    
    Budget(int y, int m, double l) : year(y), month(m), limit(l) {}
    
    bool isSameMonth(const Date& date) const {
        return year == date.year && month == date.month;
    }
};

// 账单管理系统
class BillManager {
private:
    vector<Income> incomes;
    vector<Expense> expenses;
    vector<Budget> budgets;
    
public:
    // 添加收入
    void addIncome(const Date& date, double amount, const string& category, const string& note) {
        incomes.emplace_back(date, amount, category, note);
    }
    
    // 添加支出
    void addExpense(const Date& date, double amount, const string& category, const string& note) {
        expenses.emplace_back(date, amount, category, note);
    }
    
    // 设置月度预算
    void setMonthlyBudget(int year, int month, double limit) {
        // 检查是否已有该月预算，有则更新，无则添加
        for (auto& budget : budgets) {
            if (budget.year == year && budget.month == month) {
                budget.limit = limit;
                return;
            }
        }
        budgets.emplace_back(year, month, limit);
    }
    
    // 获取月度预算
    double getMonthlyBudget(const Date& date) const {
        for (const auto& budget : budgets) {
            if (budget.isSameMonth(date)) {
                return budget.limit;
            }
        }
        return 0.0; // 未设置预算
    }
    
    // 计算月度支出总额
    double calculateMonthlyExpense(const Date& date) const {
        double total = 0.0;
        for (const auto& expense : expenses) {
            if (expense.getDate().isSameMonth(date)) {
                total += expense.getAmount();
            }
        }
        return total;
    }
    
    // 显示所有账单
    void displayAllBills() const {
        cout << "\n=================================\n";
        cout << "收入记录：\n";
        if (incomes.empty()) {
            cout << "暂无收入记录\n";
        } else {
            cout << left << setw(12) << "日期"
                 << setw(10) << "金额"
                 << setw(15) << "类别"
                 << "备注" << endl;
            cout << string(50, '-') << endl;
            for (const auto& income : incomes) {
                income.display();
            }
        }
        
        cout << "\n支出记录：\n";
        if (expenses.empty()) {
            cout << "暂无支出记录\n";
        } else {
            cout << left << setw(12) << "日期"
                 << setw(10) << "金额"
                 << setw(15) << "类别"
                 << "备注" << endl;
            cout << string(50, '-') << endl;
            for (const auto& expense : expenses) {
                expense.display();
            }
        }
        cout << "=================================\n";
    }
    
    // 按日期查询账单
    void queryByDate(const Date& date) const {
        cout << "\n=================================\n";
        cout << "收入记录 (" << date.toString() << ")：\n";
        bool hasRecord = false;
        cout << left << setw(12) << "日期"
             << setw(10) << "金额"
             << setw(15) << "类别"
             << "备注" << endl;
        cout << string(50, '-') << endl;
        for (const auto& income : incomes) {
            if (income.getDate() == date) {
                income.display();
                hasRecord = true;
            }
        }
        if (!hasRecord) {
            cout << "该日期无收入记录\n";
        }
        
        cout << "\n支出记录 (" << date.toString() << ")：\n";
        hasRecord = false;
        cout << left << setw(12) << "日期"
             << setw(10) << "金额"
             << setw(15) << "类别"
             << "备注" << endl;
        cout << string(50, '-') << endl;
        for (const auto& expense : expenses) {
            if (expense.getDate() == date) {
                expense.display();
                hasRecord = true;
            }
        }
        if (!hasRecord) {
            cout << "该日期无支出记录\n";
        }
        cout << "=================================\n";
    }
    
    // 按日期范围查询账单
    void queryByDateRange(const Date& start, const Date& end) const {
        cout << "\n=================================\n";
        cout << "收入记录 (" << start.toString() << " 至 " << end.toString() << ")：\n";
        bool hasRecord = false;
        cout << left << setw(12) << "日期"
             << setw(10) << "金额"
             << setw(15) << "类别"
             << "备注" << endl;
        cout << string(50, '-') << endl;
        for (const auto& income : incomes) {
            const Date& date = income.getDate();
            if (!(date < start) && !(end < date)) {
                income.display();
                hasRecord = true;
            }
        }
        if (!hasRecord) {
            cout << "该日期范围内无收入记录\n";
        }
        
        cout << "\n支出记录 (" << start.toString() << " 至 " << end.toString() << ")：\n";
        hasRecord = false;
        cout << left << setw(12) << "日期"
             << setw(10) << "金额"
             << setw(15) << "类别"
             << "备注" << endl;
        cout << string(50, '-') << endl;
        for (const auto& expense : expenses) {
            const Date& date = expense.getDate();
            if (!(date < start) && !(end < date)) {
                expense.display();
                hasRecord = true;
            }
        }
        if (!hasRecord) {
            cout << "该日期范围内无支出记录\n";
        }
        cout << "=================================\n";
    }
    
    // 按类别查询账单
    void queryByCategory(const string& category) const {
        cout << "\n=================================\n";
        cout << "收入记录 (类别：" << category << ")：\n";
        bool hasRecord = false;
        cout << left << setw(12) << "日期"
             << setw(10) << "金额"
             << setw(15) << "类别"
             << "备注" << endl;
        cout << string(50, '-') << endl;
        for (const auto& income : incomes) {
            if (income.getCategory() == category) {
                income.display();
                hasRecord = true;
            }
        }
        if (!hasRecord) {
            cout << "该类别无收入记录\n";
        }
        
        cout << "\n支出记录 (类别：" << category << ")：\n";
        hasRecord = false;
        cout << left << setw(12) << "日期"
             << setw(10) << "金额"
             << setw(15) << "类别"
             << "备注" << endl;
        cout << string(50, '-') << endl;
        for (const auto& expense : expenses) {
            if (expense.getCategory() == category) {
                expense.display();
                hasRecord = true;
            }
        }
        if (!hasRecord) {
            cout << "该类别无支出记录\n";
        }
        cout << "=================================\n";
    }
    
    // 显示月度统计报告
    void showMonthlyReport(int year, int month) const {
        Date targetDate(year, month, 1);
        if (!targetDate.isValid()) {
            cout << "无效的年月\n";
            return;
        }
        
        double totalIncome = 0.0;
        double totalExpense = 0.0;
        
        // 统计收入
        vector<pair<string, double>> incomeByCategory;
        for (const auto& income : incomes) {
            if (income.getDate().isSameMonth(targetDate)) {
                totalIncome += income.getAmount();
                
                // 按类别统计
                bool found = false;
                for (auto& pair : incomeByCategory) {
                    if (pair.first == income.getCategory()) {
                        pair.second += income.getAmount();
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    incomeByCategory.emplace_back(income.getCategory(), income.getAmount());
                }
            }
        }
        
        // 统计支出
        vector<pair<string, double>> expenseByCategory;
        for (const auto& expense : expenses) {
            if (expense.getDate().isSameMonth(targetDate)) {
                totalExpense += expense.getAmount();
                bool found = false;
                for (auto& pair : expenseByCategory) {
                    if (pair.first == expense.getCategory()) {
                        pair.second += expense.getAmount();
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    expenseByCategory.emplace_back(expense.getCategory(), expense.getAmount());
                }
            }
        }
        
        // 显示统计结果
        cout << "\n=================================\n";
        cout << year << "年" << month << "月 收支统计报告\n";
        cout << "=================================\n";
        cout << "总收入：" << fixed << setprecision(2) << totalIncome << "元\n";
        cout << "总支出：" << fixed << setprecision(2) << totalExpense << "元\n";
        cout << "结余：" << fixed << setprecision(2) << (totalIncome - totalExpense) << "元\n\n";
        
        // 显示预算信息
        double budget = getMonthlyBudget(targetDate);
        if (budget > 0) {
            cout << "月度预算：" << fixed << setprecision(2) << budget << "元\n";
            cout << "已使用：" << fixed << setprecision(2) << totalExpense << "元\n";
            cout << "剩余预算：" << fixed << setprecision(2) << (budget - totalExpense) << "元\n\n";
        }
        
        // 收入类别统计
        cout << "收入类别统计：\n";
        if (incomeByCategory.empty()) {
            cout << "无收入记录\n";
        } else {
            for (const auto& pair : incomeByCategory) {
                cout << left << setw(15) << pair.first 
                     << pair.second << "元 (" 
                     << fixed << setprecision(1) << (pair.second / totalIncome * 100) 
                     << "%)\n";
            }
        }
        
        // 支出类别统计
        cout << "\n支出类别统计：\n";
        if (expenseByCategory.empty()) {
            cout << "无支出记录\n";
        } else {
            for (const auto& pair : expenseByCategory) {
                cout << left << setw(15) << pair.first 
                     << pair.second << "元 (" 
                     << fixed << setprecision(1) << (pair.second / totalExpense * 100) 
                     << "%)\n";
            }
        }
        cout << "=================================\n";
    }
};

// 显示主菜单
void showMenu() {
    cout << "\n=================================\n";
    cout << "欢迎使用个人账单管理系统\n";
    cout << "=================================\n";
    cout << "请选择操作：\n";
    cout << "1. 记录收入\n";
    cout << "2. 记录支出\n";
    cout << "3. 查看所有账单\n";
    cout << "4. 查询账单\n";
    cout << "5. 设置月度预算\n";
    cout << "6. 查看月度统计报告\n";
    cout << "7. 退出系统\n\n";
    cout << "请输入选项序号：";
}

// 处理收入记录
void handleIncome(BillManager& manager) {
    cout << "\n=================================\n";
    cout << "请输入收入信息：\n";
    
    string dateStr;
    Date date;
    while (true) {
        cout << "日期（YYYY-MM-DD）：";
        cin >> dateStr;
        date = parseDate(dateStr);
        if (date.isValid()) {
            break;
        }
        cout << "错误：日期格式无效，请重新输入！\n";
    }
    
    double amount;
    while (true) {
        cout << "金额：";
        cin >> amount;
        if (cin.good() && amount > 0) {
            break;
        }
        cout << "错误：金额必须为正数，请重新输入！\n";
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }
    
    cin.ignore(); // 清除输入缓冲区
    string category;
    cout << "类别（如工资、奖金等）：";
    getline(cin, category);
    
    string note;
    cout << "备注：";
    getline(cin, note);
    
    manager.addIncome(date, amount, category, note);
    cout << "收入已成功记录！\n";
    cout << "=================================\n";
}

// 处理支出记录
void handleExpense(BillManager& manager) {
    cout << "\n=================================\n";
    cout << "请输入支出信息：\n";
    
    string dateStr;
    Date date;
    while (true) {
        cout << "日期（YYYY-MM-DD）：";
        cin >> dateStr;
        date = parseDate(dateStr);
        if (date.isValid()) {
            break;
        }
        cout << "错误：日期格式无效，请重新输入！\n";
    }
    
    double amount;
    while (true) {
        cout << "金额：";
        cin >> amount;
        if (cin.good() && amount > 0) {
            break;
        }
        cout << "错误：金额必须为正数，请重新输入！\n";
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }
    
    cin.ignore(); 
    string category;
    cout << "类别（如餐饮、交通、购物等）：";
    getline(cin, category);
    
    string note;
    cout << "备注：";
    getline(cin, note);
    
    manager.addExpense(date, amount, category, note);
    cout << "支出已成功记录！\n";

    double budget = manager.getMonthlyBudget(date);
    if (budget > 0) {
        double totalExpense = manager.calculateMonthlyExpense(date);
        cout << "本月预算：" << fixed << setprecision(2) << budget << "元\n";
        cout << "已使用：" << fixed << setprecision(2) << totalExpense << "元\n";
        cout << "剩余预算：" << fixed << setprecision(2) << (budget - totalExpense) << "元\n";
    }
    
    cout << "=================================\n";
}

// 处理账单查询
void handleQuery(BillManager& manager) {
    cout << "\n=================================\n";
    cout << "请选择查询方式：\n";
    cout << "1. 按日期查询\n";
    cout << "2. 按日期范围查询\n";
    cout << "3. 按类别查询\n";
    cout << "请输入选项：";
    
    int choice;
    cin >> choice;
    
    switch (choice) {
        case 1: {
            string dateStr;
            Date date;
            while (true) {
                cout << "请输入查询日期（YYYY-MM-DD）：";
                cin >> dateStr;
                date = parseDate(dateStr);
                if (date.isValid()) {
                    break;
                }
                cout << "错误：日期格式无效，请重新输入！\n";
            }
            manager.queryByDate(date);
            break;
        }
        case 2: {
            string startStr, endStr;
            Date startDate, endDate;
            
            while (true) {
                cout << "请输入开始日期（YYYY-MM-DD）：";
                cin >> startStr;
                startDate = parseDate(startStr);
                if (startDate.isValid()) {
                    break;
                }
                cout << "错误：日期格式无效，请重新输入！\n";
            }
            
            while (true) {
                cout << "请输入结束日期（YYYY-MM-DD）：";
                cin >> endStr;
                endDate = parseDate(endStr);
                if (endDate.isValid()) {
                    if (!(endDate < startDate)) {
                        break;
                    }
                    cout << "错误：结束日期不能早于开始日期，请重新输入！\n";
                } else {
                    cout << "错误：日期格式无效，请重新输入！\n";
                }
            }
            
            manager.queryByDateRange(startDate, endDate);
            break;
        }
        case 3: {
            cin.ignore(); 
            string category;
            cout << "请输入查询类别：";
            getline(cin, category);
            manager.queryByCategory(category);
            break;
        }
        default:
            cout << "无效的选项！\n";
    }
    cout << "=================================\n";
}

// 处理设置月度预算
void handleSetBudget(BillManager& manager) {
    cout << "\n=================================\n";
    cout << "设置月度预算：\n";
    
    int year, month;
    while (true) {
        cout << "请输入年份：";
        cin >> year;
        if (cin.good() && year > 0) {
            break;
        }
        cout << "错误：无效的年份，请重新输入！\n";
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }
    
    while (true) {
        cout << "请输入月份（1-12）：";
        cin >> month;
        if (cin.good() && month >= 1 && month <= 12) {
            break;
        }
        cout << "错误：无效的月份，请重新输入！\n";
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }
    
    double limit;
    while (true) {
        cout << "请输入预算金额：";
        cin >> limit;
        if (cin.good() && limit >= 0) {
            break;
        }
        cout << "错误：预算金额不能为负数，请重新输入！\n";
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }
    
    manager.setMonthlyBudget(year, month, limit);
    cout << year << "年" << month << "月的预算已设置为" << limit << "元\n";
    cout << "=================================\n";
}

// 处理查看月度统计报告
void handleMonthlyReport(BillManager& manager) {
    cout << "\n=================================\n";
    cout << "查看月度统计报告：\n";
    
    int year, month;
    while (true) {
        cout << "请输入年份：";
        cin >> year;
        if (cin.good() && year > 0) {
            break;
        }
        cout << "错误：无效的年份，请重新输入！\n";
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }
    
    while (true) {
        cout << "请输入月份（1-12）：";
        cin >> month;
        if (cin.good() && month >= 1 && month <= 12) {
            break;
        }
        cout << "错误：无效的月份，请重新输入！\n";
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }
    
    manager.showMonthlyReport(year, month);
}
//主函数
int main() {
    BillManager manager;
    int choice;
    bool running = true;
    
    while (running) {
        showMenu();
        cin >> choice;
        
        switch (choice) {
            case 1:
                handleIncome(manager);
                break;
            case 2:
                handleExpense(manager);
                break;
            case 3:
                manager.displayAllBills();
                break;
            case 4:
                handleQuery(manager);
                break;
            case 5:
                handleSetBudget(manager);
                break;
            case 6:
                handleMonthlyReport(manager);
                break;
            case 7:
                cout << "感谢使用，再见！\n";
                running = false;
                break;
            default:
                cout << "无效的选项，请重新输入！\n";
        }
        
        if (running && choice != 7) {
            cout << "按任意键返回主菜单...";
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
            cin.get(); // 等待用户按键
        }
    }
    
    return 0;
}